package evo;

import gui.Console;
import ids.Sensor;

import java.io.File;
import java.io.IOException;
import java.util.Scanner;
import java.util.Vector;

import ns2.Topology;
import opt.FitnessFunction;
import util.Combination;
import util.FileReader;
import util.Permutation;
import util.SSIDException;
import util.StopWatch;

public class EnuSearch {

	private static String SWAP = "swap.dat";

	public Topology topology;

	public int[] bestSoFar;

	public Vector<Sensor> sensors;

	public float fitness;

	public Console console;

	public FitnessFunction fitnessfunction;

	public EnuSearch(FileReader fileReader) {
		this.topology = fileReader.getTopology();
		this.sensors = fileReader.getSensors();
		this.console = new Console();
		this.fitnessfunction = new FitnessFunction();
		this.fitness = 0;
		this.bestSoFar = new int[this.sensors.size()];
		try {
			Combination comb = new Combination(this.topology.nodes.size() - 1,
					this.sensors.size());
			comb.choose1(0, 0);
			comb.output.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void search() throws IOException {
		Scanner scanner = new Scanner(new File(SWAP));
		int count = 0;
		try {
			while (scanner.hasNextLine()) {
				count++;
				if (count % 5000 == 0) {
					this.console.println("Working in progress, " + count
							+ " combinations have been evaluated");
				}
				int[] locations = this.processLine(scanner.nextLine());

				Permutation perm = new Permutation();
				perm.permute(locations);
				String[] tmp = perm.mem.split(" ");

				int counter = 0;
				while (counter < tmp.length) {
					int[] index = new int[locations.length];
					for (int k = 0; k < locations.length; k++) {
						index[k] = Integer.parseInt(tmp[counter++]);
					}

					for (int i = 0; i < this.sensors.size(); i++) {
						this.sensors.elementAt(i).setLocation(
								this.topology.nodes.nodeAt(index[i]));
						this.sensors.elementAt(i).run();
					}

					this.fitnessfunction.checkContribution(this.sensors);
					float fit = this.fitnessfunction.evaluate(this.sensors);
					if (fit > this.fitness) {
						this.fitness = fit;
						for (int i = 0; i < this.sensors.size(); i++) {
							this.bestSoFar[i] = this.sensors.elementAt(i).location.id;
						}
					}
				}
			}
			this.console.println("We have done exhaustive search. " + count
					+ " combinations were evaluated.");
		} finally {
			scanner.close();
		}
	}

	public int[] processLine(String aline) {
		Scanner scan = new Scanner(aline);
		int[] index = new int[this.sensors.size()];
		for (int i = 0; i < this.sensors.size(); i++) {
			index[i] = scan.nextInt();
		}
		scan.close();
		return index;
	}

	public void setConsole(Console console) {
		this.console = console;
	}

	public String print() {
		StringBuffer result = new StringBuffer();
		result.append("The best placement by an exhaustive search ( score "
				+ this.fitness + " ):\n");
		for (int i = 0; i < this.bestSoFar.length; i++) {
			result.append("Node " + this.bestSoFar[i] + "\n");
		}

		for (int i = 0; i < this.sensors.size(); i++) {
			this.sensors.elementAt(i).setLocation(
					this.topology.nodes.getNode(this.bestSoFar[i]));
			this.sensors.elementAt(i).run();
		}
		result.append(this.fitnessfunction.evaluateAndPrint(this.sensors));
		return result.toString();
	}

	public static void main(String[] args) throws IOException, SSIDException {
		FileReader fileReader = null;
		try {
			if (args.length != 3)
				throw new SSIDException(
						"3 parameters are required to run the program.\n");
			else {
				fileReader = new FileReader(new File(args[0]),
						new File(args[1]), new File(args[2]));
				fileReader.readTraceFile();
				fileReader.readTopologyFile();
				fileReader.readSensorSettings();
				fileReader.process();
			}
		} catch (SSIDException e) {
			System.err.println(e.getMessage());
			System.err.print(e.getExSearchUsage());
			System.exit(1);
		}
		EnuSearch exh = new EnuSearch(fileReader);
		System.out.println("Search starts at : " + StopWatch.getCurrentTime());
		exh.search();
		System.out.print(exh.print());
		System.out.println("Search ends at : " + StopWatch.getCurrentTime());
	}
}
